#include <eval.h>
#include <movegen.h>
#include <position.h>
#include <stats.h>

#include <stdlib.h>
#include <time.h>

#define PAWN_HASH_SIZE (1 << 18)  // a power of two
#define PAWN_HASH_MASK (PAWN_HASH_SIZE - 1)
#define MATERIAL_HASH_SIZE (1 << 9)
#define MATERIAL_HASH_MASK (MATERIAL_HASH_SIZE - 1)
#define INV_BY_STM(v, stm) ((v) * (1 - 2 * (stm)))

// In order to do lazy evaluation, keep the maximum for each stage.
int max_positional[2] = {INF_VAL, INF_VAL};
int new_max_positional[2] = {0, 0};


#if 1  // !!!!!!!!!!

int maxvals[7][2] = {
  {0, 0}, {0, 0}, {0, 0},
  {0, 0}, {0, 0}, {0, 0}, {0, 0}
};
static void update_maxvals(int* s, int p)
{
  for (int phase = 0; phase < 2; phase++) {
    int v = s[phase] < 0 ? -s[phase] : s[phase];
    if (v > maxvals[p][phase])
      maxvals[p][phase] = v; 
  }
}

void print_maxvals()
{
  for (int i = PAWN; i <= EMPTY; i++)
    printf("!!! %d\t%d\n", maxvals[i][0], maxvals[i][1]);
}

#endif



/*
 * TODO:
 * - backward pawns
 * - rooks connection
 * - control of the center
 * - determine the maximal positional score
 * - lazy evaluation
 * - move constants inside the appropriate functions
 * - include king position in pawn hash
 */


#ifndef NDEBUG
  static int init = 0;
#endif


typedef struct pawn_structure_t
{
  int16_t score[2];
  uint8_t semiopen_file[2];
  uint8_t pawn_shelter[2];  // to be mapped with safety_lut
  bitboard_t outposts;  // half for white, half for black
} pawn_structure_t;


static const int safety_lut[16] = {
  // lut[x] = int(-40 + 120.0 / (1.0 + exp(-0.4 * (x - 6))))
  -30,-25,-19,-12, -2,  8, 20, 31,
   42, 52, 59, 65, 70, 73, 75, 76
};


/* By phase and square: ranks 1-4 are bonus for black, ranks 5-8 for
   white. */
static const int outposts_val[2][64] = {
  // Midgame.
  {
    -5,  -5, -10, -15, -15, -10,  -5, -5,
    -5, -10, -15, -20, -20, -15, -10, -5,
    -5, -15, -25, -35, -35, -25, -15, -5,
    -5, -10, -15, -20, -20, -15, -10, -5,
    5, 10, 15, 20, 20, 15, 10, 5,
    5, 15, 25, 35, 35, 25, 15, 5,
    5, 10, 15, 20, 20, 15, 10, 5,
    5,  5, 10, 15, 15, 10,  5, 5
  },
  // Endgame.
  {
    -3, -3,  -6,  -9,  -9,  -6, -3, -3,
    -3, -6,  -9, -12, -12,  -9, -6, -3,
    -3, -9, -15, -21, -21, -15, -9, -3,
    -3, -6,  -9, -12, -12,  -9, -6, -3,
    3, 6,  9, 12, 12,  9, 6, 3,
    3, 9, 15, 21, 21, 15, 9, 3,
    3, 6,  9, 12, 12,  9, 6, 3,
    3, 3,  6,  9,  9,  6, 3, 3
  }
};


typedef struct pawn_hash_record_t
{
  uint64_t key;
  pawn_structure_t structure;
} pawn_hash_record_t;

static pawn_hash_record_t pawn_table[PAWN_HASH_SIZE];


typedef struct material_info_t
{
  // Scores are positive for white, negative for black.
  int16_t score[2];
  int16_t phase;
  uint16_t unused;
} material_info_t;

typedef struct material_hash_record_t
{
  hash_key_t signature;
  material_info_t info;
} material_hash_record_t;

static material_hash_record_t material_table[MATERIAL_HASH_SIZE];

static int random_eval = 0;


const int pieces_values[7] = {
  100,  // pawn
  320,  // knight
  330,  // bishop
  500,  // rook
  900   // queen
};


static int passed_pawn_val[2][2][8] = {
  // by side, phase and rank
  {{0, 10, 12, 15, 20, 28, 30, 0},
   {0, 60, 60, 80, 100, 140, 200, 0}},
  {}
};


const int isolated_pawn_val[2] = {-30, -40};
const int doubled_pawn_val[2] = {-30, -60};
const int bishop_pair_val[2] = {20, 40};
const int king_on_open_val[2] = {-50, 0};
const int king_on_semiopen_val[2] = {-30, 0};


/* Remember that the first rank is on top. The values for black pieces
   is computed in eval_init by reversing the tables for white. */
static int piece_table[2][6][2][64] = {
  // by side, piece, phase, and square
  // pawns
  {{{
      0,  0,  0,  0,  0,  0,  0,  0,
      5, 10, 10,-20,-20, 10, 10,  5,
      5, -5,-10,  0,  0,-10, -5,  5,
      0,  0,  0, 20, 20,  0,  0,  0,
      5,  5, 10, 25, 25, 10,  5,  5,
      10, 10, 20, 30, 30, 20, 10, 10,
      50, 50, 50, 50, 50, 50, 50, 50,
      0,  0,  0,  0,  0,  0,  0,  0
    }, {
      0,  0,  0,  0,  0,  0,  0,  0,
      0,  0,  0,  0,  0,  0,  0,  0,
      10, 10, 10, 10, 10, 10, 10, 10,
      25, 25, 25, 25, 25, 25, 25, 25,
      30, 30, 30, 30, 30, 20, 10, 10,
      50, 50, 50, 50, 50, 50, 50, 50,
      100,100,100,100,100,100,100,100,
      0,  0,  0,  0,  0,  0,  0,  0
    }},
  // knights
  {{
      -50,-40,-30,-30,-30,-30,-40,-50,
      -40,-20,  0,  5,  5,  0,-20,-40,
      -30,  5, 10, 15, 15, 10,  5,-30,
      -30,  0, 15, 20, 20, 15,  0,-30,
      -30,  5, 15, 20, 20, 15,  5,-30,
      -30,  0, 10, 15, 15, 10,  0,-30,
      -40,-20,  0,  0,  0,  0,-20,-40,
      -50,-40,-30,-30,-30,-30,-40,-50
    }, {
      -50,-40,-30,-30,-30,-30,-40,-50,
      -40,-20,  0,  5,  5,  0,-20,-40,
      -30,  5, 10, 15, 15, 10,  5,-30,
      -30,  0, 15, 20, 20, 15,  0,-30,
      -30,  5, 15, 20, 20, 15,  5,-30,
      -30,  0, 10, 15, 15, 10,  0,-30,
      -40,-20,  0,  0,  0,  0,-20,-40,
      -50,-40,-30,-30,-30,-30,-40,-50
    }},
  // bishops
  {{
      -20,-10,-10,-10,-10,-10,-10,-20,
      -10,  5,  0,  0,  0,  0,  5,-10,
      -10, 10, 10, 10, 10, 10, 10,-10,
      -10,  0, 10, 10, 10, 10,  0,-10,
      -10,  5,  5, 10, 10,  5,  5,-10,
      -10,  0,  5, 10, 10,  5,  0,-10,
      -10,  0,  0,  0,  0,  0,  0,-10,
      -20,-10,-10,-10,-10,-10,-10,-20
    }, {
      -20,-10,-10,-10,-10,-10,-10,-20,
      -10,  0,  0,  0,  0,  0,  0,-10,
      -10,  0,  5,  5,  5,  5,  0,-10,
      -10,  0,  5, 10, 10,  5,  0,-10,
      -10,  0,  5, 10, 10,  5,  0,-10,
      -10,  0,  5,  5,  5,  5,  0,-10,
      -10,  0,  0,  0,  0,  0,  0,-10,
      -20,-10,-10,-10,-10,-10,-10,-20
    }},
  // rooks
  {{
      0,  0,  0,  5,  5,  0,  0,  0,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      5, 10, 10, 10, 10, 10, 10,  5,
      0,  0,  0,  0,  0,  0,  0,  0
    }, {
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -10,  0,  0,  0,  0,  0,  0,-10
    }},
  // queens
  {{
      -20,-10,-10, -5, -5,-10,-10,-20,
      -10,  0,  5,  0,  0,  0,  0,-10,
      -10,  5,  5,  5,  5,  5,  0,-10,
      0,  0,  5,  5,  5,  5,  0, -5,
      -5,  0,  5,  5,  5,  5,  0, -5,
      -10,  0,  5,  5,  5,  5,  0,-10,
      -10,  0,  0,  0,  0,  0,  0,-10,
      -20,-10,-10, -5, -5,-10,-10,-20
    }, {
      -10,  0,  0,  0,  0,  0,  0,-10,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -5,  0,  0,  0,  0,  0,  0, -5,
      -10,  0,  0,  0,  0,  0,  0,-10
    }},
  // kings
  {{
      10,  15, 15,  0,  5,  0, 20, 10,
      -5,  -5,  0,  0,  0,  0, -5, -5,
      -10,-10, -5, -5, -5, -5,-10,-10,
      -10,-10, -5, -5, -5, -5,-10,-10,
      -20,-20,-10,-10,-10,-10,-20,-20,
      -20,-20,-10,-10,-10,-10,-20,-20,
      -20,-20,-20,-20,-20,-20,-20,-20,
      -20,-20,-20,-20,-20,-20,-20,-20
    }, {
      -30,-20,-10, -5, -5,-10,-20,-30,
      -20,  0,  5, 10, 10,  5,  0,-20,
      -10,  5, 10, 15, 15, 10,  5,-10,
      -5,  10, 15, 30, 30, 15, 10, -5,
      -5,  10, 15, 30, 30, 15, 10, -5,
      -10,  5, 10, 15, 15, 10,  5,-10,
      -20,  0,  5, 10, 10,  5,  0,-20,
      -30,-20,-10, -5, -5,-10,-20,-30
    }}},
  { /* black pieces */ }
};  // piece_table


static bitboard_t bb_pawn_advance[2][64];
static bitboard_t bb_pawn_isolated[64];
static bitboard_t bb_pawn_passed[2][64];


// Returns a value from 0 (opening) to 256 (endgame).
static int game_phase(const position_t* pos)
{
  assert(pos != 0);

  int ret = 320;
  for (int stm = 0; stm < 2; stm++) {
    if (BB_POS_PIECES(pos, stm, QUEEN))
      ret -= 64;
    if (BB_POS_PIECES(pos, stm, ROOK)) {
      ret -= 32;
      if (BB_IS_NOT_SINGLE(BB_POS_PIECES(pos, stm, ROOK)))
	ret -= 32;
    }
  }

  bitboard_t bb = (BB_POS_PIECES(pos, WHITE, KNIGHT) |
		   BB_POS_PIECES(pos, BLACK, KNIGHT) |
		   BB_POS_PIECES(pos, WHITE, BISHOP) |
		   BB_POS_PIECES(pos, BLACK, BISHOP));
  ret -= 16 * BB_POPCOUNT(bb);
  if (ret > 256)
    return 256;
  else if (ret < 0)
    return 0;
  return ret;
}


/* Interpolates midgame and endgame scores according to the phase of
   the game. */
static int phase_adjust(int* val, int phase)
{
  assert(phase >= 0 && phase <= 256);
  return (val[0] * (256 - phase) + val[1] * phase) >> 8;
}


static pawn_structure_t pawn_structure(const position_t* pos)
{
  bitboard_t wp = BB_POS_PIECES(pos, WHITE, PAWN);
  bitboard_t bp = BB_POS_PIECES(pos, BLACK, PAWN);
  bitboard_t bb;

  // 1) Probe the pawn hash table.
  STAT_REPORT(stat_pawn_hash_probe);
  bitboard_t key = position_get_pawn_hash_key(pos);
  bitboard_t index = key & PAWN_HASH_MASK;
  pawn_hash_record_t record = pawn_table[index];
  if (record.key == key) {
    STAT_REPORT(stat_pawn_hash_hit);
    return record.structure;
  }
  int val[2] = {0, 0};

  // 2) Evaluate white pawns.
  bb = wp;
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    val[0] += piece_table[WHITE][PAWN][0][sq];
    val[1] += piece_table[WHITE][PAWN][1][sq];
    if (!(wp & bb_pawn_isolated[sq])) {
      val[0] += isolated_pawn_val[0];
      val[1] += isolated_pawn_val[1];
    }
    if (wp & bb_pawn_advance[WHITE][sq]) {
      val[0] += doubled_pawn_val[0];
      val[1] += doubled_pawn_val[1];
    }
    if (!(bp & bb_pawn_passed[WHITE][sq])) {
      val[0] += passed_pawn_val[WHITE][0][RANK(sq)];
      val[1] += passed_pawn_val[WHITE][1][RANK(sq)];
    }
  }

  // 3) Evaluate black pawns.
  bb = bp;
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    // piece_val and piece_table already change the sign
    val[0] += piece_table[BLACK][PAWN][0][sq];
    val[1] += piece_table[BLACK][PAWN][1][sq];
    if (!(bp & bb_pawn_isolated[sq])) {
      val[0] -= isolated_pawn_val[0];
      val[1] -= isolated_pawn_val[1];
    }
    if (bp & bb_pawn_advance[BLACK][sq]) {
      val[0] -= doubled_pawn_val[0];
      val[1] -= doubled_pawn_val[1];
    }
    if (!(wp & bb_pawn_passed[BLACK][sq])) {
      val[0] -= passed_pawn_val[BLACK][0][RANK(sq)];
      val[1] -= passed_pawn_val[BLACK][1][RANK(sq)];
    }
  }

  // 4) Determine open and semiopen files.
  uint8_t semiopen_file[2] = {0, 0};
  for (int file = 0; file < 8; file++) {
    bitboard_t bb = BB_FILE(file);
    if (!(wp & bb))
      semiopen_file[WHITE] |= (1 << file);
    if (!(bp & bb))
      semiopen_file[BLACK] |= (1 << file);
  }

 /*
  * 5) Pawn shelter.
  *
  * Encoded in two nibbles per side:
  * - bits 0-3: kingside
  * - bits 4-7: queenside
  *
  * Bonus (for white kingside, the others are just reversed):
  * - pawn in F2: 4 points
  * - pawn in G2: 6 points
  * - pawn in H2: 5 points
  * - pawn in F3: 1 point
  * - pawn in G3: 4 points
  * - pawn in H3: 4 points
  * Bonus for pawns in the third rank are awarded only in the
  * corresponding pawn in the second rank is missing.
  *
  * Malus
  * - black pawn in F5, G5, H5: 1 point
  * - black pawn in F4, G4, H4: 2 points
  * - black pawn in F3, G3, H3: 3 points
  *
  * The final value is clamped in the range 0-15.  It will be used to
  * compute king safety bonus depending on kings' position and
  * castling capabilities.
  */
  uint16_t pawn_shelter[2];

  // White kingside.
  int shelter = 0;
  shelter += 4 * ((wp >> F2) & 1);
  shelter += 6 * ((wp >> G2) & 1);
  shelter += 5 * ((wp >> H2) & 1);
  bb = wp & ~(wp << 8);
  shelter += 1 * ((bb >> F3) & 1);
  shelter += 4 * ((bb >> G3) & 1);
  shelter += 4 * ((bb >> H3) & 1);
  shelter -= 1 * (((bp >> F5) & 1) +
		  ((bp >> G5) & 1) +
		  ((bp >> H5) & 1));
  shelter -= 2 * (((bp >> F4) & 1) +
		  ((bp >> G4) & 1) +
		  ((bp >> H4) & 1));
  shelter -= 3 * (((bp >> F3) & 1) +
		  ((bp >> G3) & 1) +
		  ((bp >> H3) & 1));
  if (shelter < 0)
    shelter = 0;
  assert(shelter < 16);
  pawn_shelter[WHITE] = shelter;

  // White Queenside.
  shelter = 4 * ((wp >> C2) & 1);
  shelter += 6 * ((wp >> B2) & 1);
  shelter += 5 * ((wp >> A2) & 1);
  bb = wp & ~(wp << 8);
  shelter += 1 * ((bb >> C3) & 1);
  shelter += 4 * ((bb >> B3) & 1);
  shelter += 4 * ((bb >> A3) & 1);
  shelter -= 1 * (((bp >> C5) & 1) +
		  ((bp >> B5) & 1) +
		  ((bp >> A5) & 1));
  shelter -= 2 * (((bp >> C4) & 1) +
		  ((bp >> B4) & 1) +
		  ((bp >> A4) & 1));
  shelter -= 3 * (((bp >> C3) & 1) +
		  ((bp >> B3) & 1) +
		  ((bp >> A3) & 1));
  if (shelter < 0)
    shelter = 0;
  assert(shelter < 16);
  pawn_shelter[WHITE] |= shelter << 4;

 // Black kingside.
  shelter = 4 * ((bp >> F7) & 1);
  shelter += 6 * ((bp >> G7) & 1);
  shelter += 5 * ((bp >> H7) & 1);
  bb = bp & ~(bp >> 8);
  shelter += 1 * ((bb >> F6) & 1);
  shelter += 4 * ((bb >> G6) & 1);
  shelter += 4 * ((bb >> H6) & 1);
  shelter -= 1 * (((wp >> F4) & 1) +
		  ((wp >> G4) & 1) +
		  ((wp >> H4) & 1));
  shelter -= 2 * (((wp >> F5) & 1) +
		  ((wp >> G5) & 1) +
		  ((wp >> H5) & 1));
  shelter -= 3 * (((wp >> F6) & 1) +
		  ((wp >> G6) & 1) +
		  ((wp >> H6) & 1));
  if (shelter < 0)
    shelter = 0;
  assert(shelter < 16);
  pawn_shelter[BLACK] = shelter;

  // Black Queenside.
  shelter = 4 * ((bp >> C7) & 1);
  shelter += 6 * ((bp >> B7) & 1);
  shelter += 5 * ((bp >> A7) & 1);
  bb = bp & ~(bp >> 8);
  shelter += 1 * ((bb >> C6) & 1);
  shelter += 4 * ((bb >> B6) & 1);
  shelter += 4 * ((bb >> A6) & 1);
  shelter -= 1 * (((wp >> C4) & 1) +
		  ((wp >> B4) & 1) +
		  ((wp >> A4) & 1));
  shelter -= 2 * (((wp >> C5) & 1) +
		  ((wp >> B5) & 1) +
		  ((wp >> A5) & 1));
  shelter -= 3 * (((wp >> C6) & 1) +
		  ((wp >> B6) & 1) +
		  ((wp >> A6) & 1));
  if (shelter < 0)
    shelter = 0;
  assert(shelter < 16);
  pawn_shelter[BLACK] |= shelter << 4;

  // 5) Outposts.
  bitboard_t outposts = 0;
  /* An outpost is a square defended by a pawn which cannot be
     attacked by enemy pawns. Here, only outposts in the opponent's
     half of the chessboard are considered. Bishops and knights will
     receive a bous when placed in outposts. */
  
  // White.
  bb = movegen_pawns_left_captures(wp, WHITE, ~(wp | bp));
  bb |= movegen_pawns_right_captures(wp, WHITE, ~(wp | bp));
  bb &= (BB_RANK_5 | BB_RANK_6 | BB_RANK_7 | BB_RANK_8);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    if (!(bp & bb_pawn_isolated[sq] & bb_pawn_passed[WHITE][sq]))
      BB_SET(outposts, sq);
  }

  // Black.
  bb = movegen_pawns_left_captures(bp, BLACK, ~(wp | bp));
  bb |= movegen_pawns_right_captures(bp, BLACK, ~(wp | bp));
  bb &= (BB_RANK_1 | BB_RANK_2 | BB_RANK_3 | BB_RANK_4);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    if (!(wp & bb_pawn_isolated[sq] & bb_pawn_passed[BLACK][sq]))
      BB_SET(outposts, sq);
  }

  // 6) Store the score in the pawn table.
  record.key = key;
  record.structure.score[0] = val[0];
  record.structure.score[1] = val[1];
  record.structure.semiopen_file[WHITE] = semiopen_file[WHITE];
  record.structure.semiopen_file[BLACK] = semiopen_file[BLACK];
  record.structure.pawn_shelter[WHITE] = pawn_shelter[WHITE];
  record.structure.pawn_shelter[BLACK] = pawn_shelter[BLACK];
  record.structure.outposts = outposts;
  pawn_table[index] = record;

  return record.structure;
}


static material_info_t eval_material(const position_t* pos)
{
  assert(pos != 0);
  
  static const int bishop_pair_bonus = 40;
  static const int nopawn_penalty = 80;
  static const int eight_pawns_penalty = 30;

  /* 
   * Used to scale material values (the fewer the pawns, the drawish
   * the position).  Only if the difference is blow 'draw_thr' which
   * is considered enough to win without a promotion.  All this is
   * applied to endgame score only.  The values are scaled by 256.
   * This values may exceed 256 to encourage the winning side to trade
   * pieces.
   */
  static const int pawn_scale[9] = {
    16, 128, 192, 256, 300, 300, 300, 300, 300
  };
  static const int draw_thr = 400;

  hash_key_t key = position_get_material_hash_key(pos);
  key &= MATERIAL_HASH_MASK;
  hash_key_t sig = position_get_material_signature(pos);

  STAT_REPORT(stat_material_hash_probe);  
  if (material_table[key].signature == sig) {
    STAT_REPORT(stat_material_hash_hit);  
    return material_table[key].info;
  }

  int score[2];
  // White pieces.
  int wp = position_piece_count(pos, WHITE, PAWN);
  score[0] = wp * pieces_values[PAWN];
  score[1] = wp * pieces_values[PAWN];
  if (wp == 0)
    score[1] -= nopawn_penalty;
  else if (wp == 8)
    score[0] -= eight_pawns_penalty;
  int wfigs = 0;
  for (int p = KNIGHT; p < KING; p++)
    wfigs += pieces_values[p] * position_piece_count(pos, WHITE, p);
  if (position_piece_count(pos, WHITE, BISHOP) > 1)
    wfigs += bishop_pair_bonus;

  // Black pieces.
  int bp = position_piece_count(pos, BLACK, PAWN);
  score[0] -= bp * pieces_values[PAWN];
  score[1] -= bp * pieces_values[PAWN];
  if (bp == 0)
    score[1] += nopawn_penalty;
  else if (bp == 8)
    score[0] += eight_pawns_penalty;
  int bfigs = 0;
  for (int p = KNIGHT; p < KING; p++)
    bfigs += pieces_values[p] * position_piece_count(pos, BLACK, p);
  if (position_piece_count(pos, BLACK, BISHOP) > 1)
    bfigs += bishop_pair_bonus;
  
  // Endgame correction based on the number of pawns.
  int scale;
  if (wfigs - bfigs > -draw_thr &&
      wfigs - bfigs < draw_thr)
    scale = pawn_scale[(wfigs > bfigs ? wp : bp)];
  else
    scale = pawn_scale[8];
  score[0] += wfigs - bfigs;
  if (wfigs > bfigs)
    score[1] += ((wfigs - bfigs) * scale) >> 8;
  else
    score[1] -= ((bfigs - wfigs) * scale) >> 8;
  
  material_table[key].signature = sig;
  material_table[key].info.score[0] = score[0];
  material_table[key].info.score[1] = score[1];
  material_table[key].info.phase = game_phase(pos);
  
  return material_table[key].info;
}


static void eval_knights(const position_t* pos,
			 const pawn_structure_t* pstruct,
			 int* score)
{
  /* static const int mobility_bonus = 2; */
  /* static const int mean_mobility = 4; */

  score[0] = 0;
  score[1] = 0;
  
  // White.
  bitboard_t bb = BB_POS_PIECES(pos, WHITE, KNIGHT);
  /* bitboard_t safe; */
  /* bitboard_t pawns = BB_POS_PIECES(pos, BLACK, PAWN); */
  /* safe = ~movegen_pawns_left_captures(pawns, BLACK, ~BB_POS_COLOR(pos, WHITE)); */
  /* safe &= ~movegen_pawns_right_captures(pawns, BLACK,~BB_POS_COLOR(pos, WHITE)); */

  while (bb) {
    int sq = BB_LSB(bb);
    score[0] += piece_table[WHITE][KNIGHT][0][sq];
    score[1] += piece_table[WHITE][KNIGHT][1][sq];
    BB_CLEAR_LSB(bb);
    if (BB_TEST(pstruct->outposts, sq)) {
      score[0] += outposts_val[0][sq];
      score[1] += outposts_val[1][sq];
    }
    // Mobility.
    /* bitboard_t m = movegen_knight_attacks(sq) & safe; */
    /* int v = (BB_POPCOUNT(m) - mean_mobility) * mobility_bonus; */
    /* score[0] += v; */
    /* score[1] += v; */
  }

  // Black.
  bb = BB_POS_PIECES(pos, BLACK, KNIGHT);
  /* pawns = BB_POS_PIECES(pos, WHITE, PAWN); */
  /* safe = ~movegen_pawns_left_captures(pawns, WHITE, ~BB_POS_COLOR(pos, BLACK)); */
  /* safe &= ~movegen_pawns_right_captures(pawns, WHITE,~BB_POS_COLOR(pos, BLACK)); */

  while (bb) {
    int sq = BB_LSB(bb);
    score[0] += piece_table[BLACK][KNIGHT][0][sq];
    score[1] += piece_table[BLACK][KNIGHT][1][sq];
    BB_CLEAR_LSB(bb);
    if (BB_TEST(pstruct->outposts, sq)) {
      score[0] += outposts_val[0][sq];
      score[1] += outposts_val[1][sq];
    }
    // Mobility.
    /* bitboard_t m = movegen_knight_attacks(sq) & safe; */
    /* int v = (BB_POPCOUNT(m) - mean_mobility) * mobility_bonus; */
    /* score[0] -= v; */
    /* score[1] -= v; */
  }

  score[0] = INV_BY_STM(score[0], position_get_stm(pos));
  score[1] = INV_BY_STM(score[1], position_get_stm(pos));
}


static void eval_bishops(const position_t* pos,
			 const pawn_structure_t* pstruct,
			 int* score)
{
  /* static const int mobility_bonus = 2; */
  /* static const int mean_mobility = 7; */

  // bitboard_t all = BB_POS_ALL(pos);

  score[0] = 0;
  score[1] = 0;

  // White.
  bitboard_t bb = BB_POS_PIECES(pos, WHITE, BISHOP);
  /* bitboard_t safe; */
  /* bitboard_t pawns = BB_POS_PIECES(pos, BLACK, PAWN); */
  /* safe = ~movegen_pawns_left_captures(pawns, BLACK, ~BB_POS_COLOR(pos, WHITE)); */
  /* safe &= ~movegen_pawns_right_captures(pawns, BLACK,~BB_POS_COLOR(pos, WHITE)); */

  while (bb) {
    int sq = BB_LSB(bb);
    score[0] += piece_table[WHITE][BISHOP][0][sq];
    score[1] += piece_table[WHITE][BISHOP][1][sq];
    BB_CLEAR_LSB(bb);
    if (BB_TEST(pstruct->outposts, sq)) {
      score[0] += outposts_val[0][sq];
      score[1] += outposts_val[1][sq];
    }
    // Mobility.
    /* bitboard_t m = movegen_bishop_attacks(sq, all) & safe; */
    /* int v = (BB_POPCOUNT(m) - mean_mobility) * mobility_bonus; */
    /* score[0] += v; */
    /* score[1] += v; */
  }

  // Black.
  bb = BB_POS_PIECES(pos, BLACK, BISHOP);
  /* pawns = BB_POS_PIECES(pos, WHITE, PAWN); */
  /* safe = ~movegen_pawns_left_captures(pawns, WHITE, ~BB_POS_COLOR(pos, BLACK)); */
  /* safe &= ~movegen_pawns_right_captures(pawns, WHITE,~BB_POS_COLOR(pos, BLACK)); */

  while (bb) {
    int sq = BB_LSB(bb);
    score[0] += piece_table[BLACK][BISHOP][0][sq];
    score[1] += piece_table[BLACK][BISHOP][1][sq];
    BB_CLEAR_LSB(bb);
    if (BB_TEST(pstruct->outposts, sq)) {
      score[0] += outposts_val[0][sq];
      score[1] += outposts_val[1][sq];
    }
    // Mobility.
    /* bitboard_t m = movegen_bishop_attacks(sq, all) & safe; */
    /* int v = (BB_POPCOUNT(m) - mean_mobility) * mobility_bonus; */
    /* score[0] -= v; */
    /* score[1] -= v; */
  }

  score[0] = INV_BY_STM(score[0], position_get_stm(pos));
  score[1] = INV_BY_STM(score[1], position_get_stm(pos));
}


static void eval_rooks(const position_t* pos,
		       const pawn_structure_t* pstruct,
		       int* score)
{
  static const int rook_on_open_val = 60;
  static const int rook_on_semiopen_val = 40;
  /* static const int mobility_bonus[2] = {1, 2}; */
  /* static const int mean_mobility = 7; */

  score[0] = 0;
  score[1] = 0;
  
  // bitboard_t all = BB_POS_ALL(pos);

  // White.
  bitboard_t bb = BB_POS_PIECES(pos, WHITE, ROOK);
  /* bitboard_t safe; */
  /* bitboard_t pawns = BB_POS_PIECES(pos, BLACK, PAWN); */
  /* safe = ~movegen_pawns_left_captures(pawns, BLACK, ~BB_POS_COLOR(pos, WHITE)); */
  /* safe &= ~movegen_pawns_right_captures(pawns, BLACK,~BB_POS_COLOR(pos, WHITE)); */

  while (bb) {
    int sq = BB_LSB(bb);
    score[0] += piece_table[WHITE][ROOK][0][sq];
    score[1] += piece_table[WHITE][ROOK][1][sq];
    int file = FILE(sq);
    unsigned int white_open = ((pstruct->semiopen_file[WHITE] >> file) & 1);
    unsigned int black_open = ((pstruct->semiopen_file[BLACK] >> file) & 1);
    if (white_open) {
      if (black_open) {
    	score[0] += rook_on_open_val;
    	score[1] += rook_on_open_val;
      } else {
    	score[0] += rook_on_semiopen_val;
    	score[1] += rook_on_semiopen_val;
      }
    }
    BB_CLEAR_LSB(bb);
    // Mobility.
    /* bitboard_t m = movegen_rook_attacks(sq, all) & safe; */
    /* int v = BB_POPCOUNT(m) - mean_mobility; */
    /* score[0] += v * mobility_bonus[0]; */
    /* score[1] += v * mobility_bonus[1]; */
  }

  // Black.
  bb = BB_POS_PIECES(pos, BLACK, ROOK);
  /* pawns = BB_POS_PIECES(pos, WHITE, PAWN); */
  /* safe = ~movegen_pawns_left_captures(pawns, WHITE, ~BB_POS_COLOR(pos, BLACK)); */
  /* safe &= ~movegen_pawns_right_captures(pawns, WHITE,~BB_POS_COLOR(pos, BLACK)); */

  while (bb) {
    int sq = BB_LSB(bb);
    score[0] += piece_table[BLACK][ROOK][0][sq];
    score[1] += piece_table[BLACK][ROOK][1][sq];
    int file = FILE(sq);
    unsigned int white_open = ((pstruct->semiopen_file[WHITE] >> file) & 1);
    unsigned int black_open = ((pstruct->semiopen_file[BLACK] >> file) & 1);
    if (black_open) {
      if (white_open) {
	score[0] -= rook_on_open_val;
	score[1] -= rook_on_open_val;
      } else {
	score[0] -= rook_on_semiopen_val;
	score[1] -= rook_on_semiopen_val;
      }
    }
    BB_CLEAR_LSB(bb);
    // Mobility.
    /* bitboard_t m = movegen_rook_attacks(sq, all) & safe; */
    /* int v = BB_POPCOUNT(m) - mean_mobility; */
    /* score[0] -= v * mobility_bonus[0]; */
    /* score[1] -= v * mobility_bonus[1]; */
  }

  score[0] = INV_BY_STM(score[0], position_get_stm(pos));
  score[1] = INV_BY_STM(score[1], position_get_stm(pos));
}


static void eval_queens(const position_t* pos,
			const pawn_structure_t* pstruct,
			int* score)
{
  /* static const int mobility_bonus[2] = {1, 2}; */
  /* static const int mean_mobility = 10; */

  score[0] = 0;
  score[1] = 0;

  // bitboard_t all = BB_POS_ALL(pos);
  
  // White.
  bitboard_t bb = BB_POS_PIECES(pos, WHITE, QUEEN);
  /* bitboard_t safe; */
  /* bitboard_t pawns = BB_POS_PIECES(pos, BLACK, PAWN); */
  /* safe = ~movegen_pawns_left_captures(pawns, BLACK, ~BB_POS_COLOR(pos, WHITE)); */
  /* safe &= ~movegen_pawns_right_captures(pawns, BLACK,~BB_POS_COLOR(pos, WHITE)); */

  while (bb) {
    int sq = BB_LSB(bb);
    score[0] += piece_table[WHITE][QUEEN][0][sq];
    score[1] += piece_table[WHITE][QUEEN][1][sq];
    BB_CLEAR_LSB(bb);
    // Mobility.
    /* bitboard_t m = (movegen_rook_attacks(sq, all) | */
    /* 		    movegen_bishop_attacks(sq, all)) & safe; */
    /* int v = BB_POPCOUNT(m) - mean_mobility; */
    /* score[0] += v * mobility_bonus[0]; */
    /* score[1] += v * mobility_bonus[1]; */
  }

  // Black.
  bb = BB_POS_PIECES(pos, BLACK, QUEEN);
  /* pawns = BB_POS_PIECES(pos, WHITE, PAWN); */
  /* safe = ~movegen_pawns_left_captures(pawns, WHITE, ~BB_POS_COLOR(pos, BLACK)); */
  /* safe &= ~movegen_pawns_right_captures(pawns, WHITE,~BB_POS_COLOR(pos, BLACK)); */

  while (bb) {
    int sq = BB_LSB(bb);
    score[0] += piece_table[BLACK][QUEEN][0][sq];
    score[1] += piece_table[BLACK][QUEEN][1][sq];
    BB_CLEAR_LSB(bb);
    // Mobility.
    /* bitboard_t m = (movegen_rook_attacks(sq, all) | */
    /* 		    movegen_bishop_attacks(sq, all)) & safe; */
    /* int v = BB_POPCOUNT(m) - mean_mobility; */
    /* score[0] -= v * mobility_bonus[0]; */
    /* score[1] -= v * mobility_bonus[1]; */
  }

  score[0] = INV_BY_STM(score[0], position_get_stm(pos));
  score[1] = INV_BY_STM(score[1], position_get_stm(pos));
}


static void eval_kings(const position_t* pos,
		       const pawn_structure_t* pstruct,
		       int* score)
{
  assert(pos != 0);
  assert(pstruct != 0);
  assert(BB_POS_PIECES(pos, WHITE, KING) != 0);
  assert(BB_POS_PIECES(pos, BLACK, KING) != 0);

  bitboard_t wk = BB_POS_PIECES(pos, WHITE, KING);
  bitboard_t bk = BB_POS_PIECES(pos, BLACK, KING);

  score[0] = 0;
  score[1] = 0;

  // 1) Position
  int wsq = BB_LSB(wk);
  score[0] += piece_table[WHITE][KING][0][wsq];
  score[1] += piece_table[WHITE][KING][1][wsq];
  int bsq = BB_LSB(bk);
  // piece_table already changes the sign
  score[0] += piece_table[BLACK][KING][0][bsq];
  score[1] += piece_table[BLACK][KING][1][bsq];

  // 2) King on open/semiopen file
  int king_file = FILE(wsq);
  int white_open = ((pstruct->semiopen_file[WHITE] >> king_file) & 1);
  int black_open = ((pstruct->semiopen_file[BLACK] >> king_file) & 1);
  if (black_open) {
    if (white_open) {
      score[0] += king_on_open_val[0];
      score[1] += king_on_open_val[1];
    } else {
      score[0] += king_on_semiopen_val[0];
      score[1] += king_on_semiopen_val[1];
    }
  }
  king_file = FILE(bsq);
  white_open = ((pstruct->semiopen_file[WHITE] >> king_file) & 1);
  black_open = ((pstruct->semiopen_file[BLACK] >> king_file) & 1);
  if (white_open) {
    if (black_open) {
      score[0] -= king_on_open_val[0];
      score[1] -= king_on_open_val[1];
    } else {
      score[0] -= king_on_semiopen_val[0];
      score[1] -= king_on_semiopen_val[1];
    }
  }

  // 3) Safety (applies only to midgame score).
  if (wk & (BB_SINGLE(F1) | BB_SINGLE(G1) | BB_SINGLE(H1))) {
    score[0] += safety_lut[pstruct->pawn_shelter[WHITE] & 15];
  } else if (wk & (BB_SINGLE(A1) | BB_SINGLE(B1) | BB_SINGLE(C1))) {
    score[0] += safety_lut[pstruct->pawn_shelter[WHITE] >> 4];
  } else {
    /* When castling is possible, pawn shelters are worth one fourth
       the sum of kingside and queenside shelter bonus (if
       positive). */
    unsigned int caps = position_get_castling_caps(pos);
    if (caps & WCASTLE_SHORT) {
      int v = safety_lut[pstruct->pawn_shelter[WHITE] & 15];
      if (v > 0)
	score[0] += (v >> 2);
    }
    if (caps & WCASTLE_LONG) {
      int v = safety_lut[pstruct->pawn_shelter[WHITE] >> 4];
      if (v > 0)
	score[0] += (v >> 2);
    }
  }

  if (bk & (BB_SINGLE(F8) | BB_SINGLE(G8) | BB_SINGLE(H8))) {
    score[0] -= safety_lut[pstruct->pawn_shelter[BLACK] & 15];
  } else if (bk & (BB_SINGLE(A8) | BB_SINGLE(B8) | BB_SINGLE(C8))) {
    score[0] -= safety_lut[pstruct->pawn_shelter[BLACK] >> 4];
  } else {
    /* When castling is possible, pawn shelters are worth one fourth
       the sum of kingside and queenside shelter bonus (if
       positive). */
    unsigned int caps = position_get_castling_caps(pos);
    if (caps & BCASTLE_SHORT) {
      int v = safety_lut[pstruct->pawn_shelter[BLACK] & 15];
      if (v > 0)
	score[0] -= (v >> 2);
    }
    if (caps & BCASTLE_LONG) {
      int v = safety_lut[pstruct->pawn_shelter[BLACK] >> 4];
      if (v > 0)
	score[0] -= (v >> 2);
    }
  }

  score[0] = INV_BY_STM(score[0], position_get_stm(pos));
  score[1] = INV_BY_STM(score[1], position_get_stm(pos));
}



static void eval_mobility(const position_t* pos,
			  const pawn_structure_t* pstruct,
			  int* score)
{
  static const int n_mobility_bonus[2] = {2, 2};
  static const int b_mobility_bonus[2] = {2, 2};
  static const int r_mobility_bonus[2] = {1, 2};
  static const int q_mobility_bonus[2] = {1, 2};
  static const int n_mean = 4;
  static const int b_mean = 7;
  static const int r_mean = 7;
  static const int q_mean = 10;

  score[0] = 0;
  score[1] = 0;

  bitboard_t all = BB_POS_ALL(pos);
  bitboard_t pawns;
  bitboard_t wsafe;
  pawns = BB_POS_PIECES(pos, BLACK, PAWN);
  wsafe = ~movegen_pawns_left_captures(pawns, BLACK, ~BB_POS_COLOR(pos, WHITE));
  wsafe &= ~movegen_pawns_right_captures(pawns,BLACK,~BB_POS_COLOR(pos, WHITE));

  bitboard_t bsafe;
  pawns = BB_POS_PIECES(pos, WHITE, PAWN);
  bsafe = ~movegen_pawns_left_captures(pawns, WHITE, ~BB_POS_COLOR(pos, BLACK));
  bsafe &= ~movegen_pawns_right_captures(pawns,WHITE,~BB_POS_COLOR(pos, BLACK));
  
  // White knights.
  bitboard_t bb = BB_POS_PIECES(pos, WHITE, KNIGHT);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    bitboard_t m = movegen_knight_attacks(sq) & wsafe;
    int v = (BB_POPCOUNT(m) - n_mean);
    score[0] += v * n_mobility_bonus[0];
    score[1] += v * n_mobility_bonus[1];
  }

  // Black knights.
  bb = BB_POS_PIECES(pos, BLACK, KNIGHT);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    bitboard_t m = movegen_knight_attacks(sq) & bsafe;
    int v = (BB_POPCOUNT(m) - n_mean);
    score[0] -= v * n_mobility_bonus[0];
    score[1] -= v * n_mobility_bonus[1];
  }

  // White bishops.
  bb = BB_POS_PIECES(pos, WHITE, BISHOP);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    bitboard_t m = movegen_bishop_attacks(sq, all) & wsafe;
    int v = (BB_POPCOUNT(m) - b_mean);
    score[0] += v * b_mobility_bonus[0];
    score[1] += v * b_mobility_bonus[1];
  }

  // Black bishops.
  bb = BB_POS_PIECES(pos, BLACK, BISHOP);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    bitboard_t m = movegen_bishop_attacks(sq, all) & bsafe;
    int v = (BB_POPCOUNT(m) - b_mean);
    score[0] -= v * b_mobility_bonus[0];
    score[1] -= v * b_mobility_bonus[1];
  }

  // White rooks.
  bb = BB_POS_PIECES(pos, WHITE, ROOK);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    bitboard_t m = movegen_rook_attacks(sq, all) & wsafe;
    int v = (BB_POPCOUNT(m) - r_mean);
    score[0] += v * r_mobility_bonus[0];
    score[1] += v * r_mobility_bonus[1];
  }

  // Black rooks.
  bb = BB_POS_PIECES(pos, BLACK, ROOK);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    bitboard_t m = movegen_rook_attacks(sq, all) & bsafe;
    int v = (BB_POPCOUNT(m) - r_mean);
    score[0] -= v * r_mobility_bonus[0];
    score[1] -= v * r_mobility_bonus[1];
  }

  // White queens.
  bb = BB_POS_PIECES(pos, WHITE, QUEEN);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    bitboard_t m = movegen_rook_attacks(sq, all);
    m = (m | movegen_bishop_attacks(sq, all)) & wsafe;
    int v = (BB_POPCOUNT(m) - q_mean);
    score[0] += v * q_mobility_bonus[0];
    score[1] += v * q_mobility_bonus[1];
  }

  // Black queens.
  bb = BB_POS_PIECES(pos, BLACK, QUEEN);
  while (bb) {
    int sq = BB_LSB(bb);
    BB_CLEAR_LSB(bb);
    bitboard_t m = movegen_rook_attacks(sq, all);
    m = (m | movegen_bishop_attacks(sq, all)) & bsafe;
    int v = (BB_POPCOUNT(m) - q_mean);
    score[0] -= v * q_mobility_bonus[0];
    score[1] -= v * q_mobility_bonus[1];
  }
  
  score[0] = INV_BY_STM(score[0], position_get_stm(pos));
  score[1] = INV_BY_STM(score[1], position_get_stm(pos));
}


void eval_init()
{
  atexit(print_maxvals);  // !!!!!

  eval_reset_max_positional_value();

  // Reverse the piece tables for the black player.
  for (int phase = 0; phase < 2; phase++) {
    for (int p = PAWN; p <= KING; p++) {
      for (int sq = 0; sq < 64; sq++) {
	int rev = SQUARE(FILE(sq), 7 - RANK(sq));
	piece_table[BLACK][p][phase][sq] = -piece_table[WHITE][p][phase][rev];
      }
    }
  }

  // Reverse the rank for black passed pawns.
  for (int phase = 0; phase < 2; phase++)
    for (int rank = 0; rank < 8; rank++)
      passed_pawn_val[BLACK][phase][rank] =
	passed_pawn_val[WHITE][phase][7 - rank];

  // Compute the bitboards for pawn structure evaluation.
  for (int sq = 0; sq < 64; sq++) {
    bitboard_t bb = 0;
    int rank = RANK(sq);
    int file = FILE(sq);

    // advance
    for (int r = rank + 1; r < 8; r++)
      BB_SET(bb, SQUARE(file,r));
    bb_pawn_advance[WHITE][sq] = bb;
    bb = 0;
    for (int r = rank - 1; r >= 0; r--)
      BB_SET(bb, SQUARE(file,r));
    bb_pawn_advance[BLACK][sq] = bb;

    // isolated
    bb = 0;
    for (int r = 0; r < 8; r++) {
      if (file > 0)
	BB_SET(bb, SQUARE(file - 1, r));
      if (file < 7)
	BB_SET(bb, SQUARE(file + 1, r));
    }
    bb_pawn_isolated[sq] = bb;
  }

  for (int sq = 0; sq < 64; sq++) {
    bitboard_t bb;
    int rank = RANK(sq);
    int file = FILE(sq);
    // passed
    for (int s = 0; s < 2; s++) {
      bb = bb_pawn_advance[s][sq];
      if (file > 0)
	bb |= bb_pawn_advance[s][SQUARE(file - 1, rank)];
      if (file < 7)
	bb |= bb_pawn_advance[s][SQUARE(file + 1, rank)];
      bb_pawn_passed[s][sq] = bb;
    }
  }
  assert((init = 1));

  for (size_t i = 0; i < PAWN_HASH_SIZE; i++) {
    pawn_table[i].key = 0;
    pawn_table[i].structure.score[0] = 0;
    pawn_table[i].structure.score[1] = 0;
    pawn_table[i].structure.semiopen_file[WHITE] = 255;
    pawn_table[i].structure.semiopen_file[BLACK] = 255;
    pawn_table[i].structure.pawn_shelter[WHITE] = 0;
    pawn_table[i].structure.pawn_shelter[BLACK] = 0;
  }

  for (size_t i = 0; i < MATERIAL_HASH_SIZE; i++) {
    material_table[i].signature = 0;
    material_table[i].info.score[0] = 0;
    material_table[i].info.score[1] = 0;
    material_table[i].info.phase = 256;
  }
}


void eval_reset_max_positional_value()
{
  max_positional[0] = INF_VAL;
  max_positional[1] = INF_VAL;
  new_max_positional[0] = 0;
  new_max_positional[1] = 0;
}


int eval_max_positional_value()
{
  return max_positional[0];
}


void eval_update_max_positional_value()
{
  max_positional[0] = new_max_positional[0];
  max_positional[1] = new_max_positional[1];
  new_max_positional[0] = 0;
  new_max_positional[1] = 0;
}


int eval(const struct position_t* pos, int alpha, int beta)
{
  assert(init);
  assert(pos != 0);
  
  int stm = position_get_stm(pos);
  material_info_t mat_info = eval_material(pos);
  int val[2];
  val[0] = INV_BY_STM(mat_info.score[0], stm);
  val[1] = INV_BY_STM(mat_info.score[1], stm);
  int material = phase_adjust(val, mat_info.phase);

  if (material + max_positional[0] + 25 <= alpha)
    return material + max_positional[0] + 25;
  if (material - max_positional[0] - 25 >= beta)
    return material - max_positional[0] - 25;
  pawn_structure_t pawn_struct = pawn_structure(pos);
  val[0] += INV_BY_STM(pawn_struct.score[0], stm);
  val[1] += INV_BY_STM(pawn_struct.score[1], stm);
  int tmp[2];
  eval_kings(pos, &pawn_struct, tmp);
  val[0] += tmp[0];
  val[1] += tmp[1];
  update_maxvals(tmp, KING); // !!!
  eval_knights(pos, &pawn_struct, tmp);
  val[0] += tmp[0];
  val[1] += tmp[1];
  update_maxvals(tmp, KNIGHT); // !!!
  eval_bishops(pos, &pawn_struct, tmp);
  val[0] += tmp[0];
  val[1] += tmp[1];
  update_maxvals(tmp, BISHOP); // !!!
  eval_rooks(pos, &pawn_struct, tmp);
  val[0] += tmp[0];
  val[1] += tmp[1];
  update_maxvals(tmp, ROOK); // !!!
  eval_queens(pos, &pawn_struct, tmp);
  val[0] += tmp[0];
  val[1] += tmp[1];
  update_maxvals(tmp, QUEEN); // !!!

  int nomobility = phase_adjust(val, mat_info.phase);
  if (nomobility + max_positional[1] + 15 <= alpha)
    return nomobility + max_positional[1] + 15;
  if (nomobility - max_positional[1] - 15 >= beta)
    return nomobility - max_positional[1] - 15;

  eval_mobility(pos, &pawn_struct, tmp);
  val[0] += tmp[0];
  val[1] += tmp[1];
  update_maxvals(tmp, 6); // !!!
  if (random_eval)
    val[0] += (rand() % 11) - 5;

  int score = phase_adjust(val, mat_info.phase);
  int positional = score - material;
  if (positional < 0)
    positional = -positional;
  if (positional > new_max_positional[0])
    new_max_positional[0] = positional;
  if (positional > max_positional[0])
    max_positional[0] = positional;

  positional = score - nomobility;
  if (positional < 0)
    positional = -positional;
  if (positional > new_max_positional[1])
    new_max_positional[1] = positional;
  if (positional > max_positional[1])
    max_positional[1] = positional;

  return score;
}


void eval_detail(const struct position_t* pos,
		 evaluation_t* ev)
{
  assert(pos != 0);
  assert(ev != 0);

  int stm = position_get_stm(pos);
  material_info_t mat_info = eval_material(pos);
  ev->phase = mat_info.phase;
  ev->material[0] = INV_BY_STM(mat_info.score[0], stm);
  ev->material[1] = INV_BY_STM(mat_info.score[1], stm);
  pawn_structure_t pawn_struct = pawn_structure(pos);
  ev->pawns[0] = INV_BY_STM(pawn_struct.score[0], stm);
  ev->pawns[1] = INV_BY_STM(pawn_struct.score[1], stm);
  eval_kings(pos, &pawn_struct, ev->kings);
  eval_knights(pos, &pawn_struct, ev->knights);
  eval_bishops(pos, &pawn_struct, ev->bishops);
  eval_rooks(pos, &pawn_struct, ev->rooks);
  eval_queens(pos, &pawn_struct, ev->queens);

  for (int phase = 0; phase < 2; phase ++) {
    ev->phase_total[phase] = (ev->material[phase] + 
			      ev->pawns[phase] +
			      ev->kings[phase] +
			      ev->knights[phase] +
			      ev->bishops[phase] +
			      ev->rooks[phase] + 
			      ev->queens[phase]);
  }
  ev->total = phase_adjust(ev->phase_total, ev->phase);
}


void eval_set_random(int r)
{
  if (r) {
    srand(time(0));
    random_eval = 1;
  } else {
    random_eval = 0;
  }
}


int eval_pawn_table_size()
{
  return (PAWN_HASH_SIZE * sizeof(pawn_hash_record_t)) / (1024 * 1024);
}
